package com.coalmine.api.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.coalmine.api.domain.ApiDatasource;
import com.coalmine.api.mapper.ApiConfigMapper;
import com.coalmine.api.mapper.ApiDatasourceMapper;
import com.coalmine.api.service.IApiDatasourceService;
import com.coalmine.api.util.DESUtils;
import com.coalmine.api.util.PoolManager;
import com.coalmine.api.util.RedisPoolManager;
import com.coalmine.api.util.UUIDUtil;
import com.coalmine.common.constant.Constants;
import com.coalmine.common.constant.HttpStatus;
import com.coalmine.common.core.redis.RedisCache;
import com.coalmine.common.exception.ServiceException;
import com.coalmine.common.utils.SecurityUtils;
import com.coalmine.common.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.PostConstruct;
import java.util.Collection;
import java.util.Date;
import java.util.List;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 尚郑
 * @since 2022-04-01
 */
@Service
@Slf4j
public class ApiDatasourceServiceImpl extends ServiceImpl<ApiDatasourceMapper, ApiDatasource> implements IApiDatasourceService {

    @Autowired
    ApiDatasourceMapper apiDatasourceMapper;

    @Autowired
    ApiConfigMapper apiConfigMapper;

    @Autowired
    private RedisCache redisCache;

    /**
     * 新增数据源
     */
    @Transactional
    public int add(ApiDatasource apiDatasource) {

        apiDatasource.setId(UUIDUtil.getUUID());
        apiDatasource.setUpdateTime(new Date());
        apiDatasource.setCreateTime(new Date());
        //新增数据源对密码加密
        try {
            apiDatasource.setPassword(DESUtils.encrypt(apiDatasource.getPassword()));
        } catch (Exception e) {
            throw new ServiceException("数据源密码加密异常", HttpStatus.ERROR);
        }
        //插入数据
        int row = apiDatasourceMapper.insert(apiDatasource);
        if (row > 0) {
            redisCache.setCacheObject(getCacheKey(apiDatasource.getId()), apiDatasource);
        }
        return row;

    }

    /**
     * 根据主键更新
     */
    //@CacheEvict(value = "datasource", key = "#apiDatasource.id")
    @Transactional
    public int update(ApiDatasource apiDatasource) {

        if(apiDatasource.getId() == null){
            throw new ServiceException("更新数据源,id不能为空！", HttpStatus.ERROR);
        }
        apiDatasource.setUpdateTime(new Date());
        //如果修改了密码, 需要对密码加密
        if (apiDatasource.isEdit_password()){
            try {
                apiDatasource.setPassword(DESUtils.encrypt(apiDatasource.getPassword()));
            } catch (Exception e) {
                throw new ServiceException("更新数据源，密码加密异常", HttpStatus.ERROR);
            }
        }
        int row = apiDatasourceMapper.updateById(apiDatasource);
        //获取更新后的数据源
        ApiDatasource data = apiDatasourceMapper.selectById(apiDatasource.getId());
        if (row > 0) {
            PoolManager.removeJdbcConnectionPool(apiDatasource.getId());
            if (StringUtils.equals("redis", apiDatasource.getType())) {
                RedisPoolManager.removeRedisConnectionPool(apiDatasource.getId());
            }
            //更新缓存
            redisCache.setCacheObject(getCacheKey(apiDatasource.getId()), data);
        }
        return row;

    }

    /**
     * 根据id删除
     */
    //@CacheEvict(value = "datasource", key = "#id")
    @Transactional
    public int delete(String id) {
        int i = apiConfigMapper.countByDatasoure(id);
        if (i == 0) {
            PoolManager.removeJdbcConnectionPool(id);
            int row = apiDatasourceMapper.deleteById(id);
            if (row > 0) {
                //更新缓存
                redisCache.deleteObject(getCacheKey(id));
            }
            return row;
        } else {
            return 0;
        }
    }

    /**
     * 根据id获取详情
     */
    //@Cacheable(value = "datasource", key = "#id", unless = "#result == null")
    public ApiDatasource detail(String id) {
        ApiDatasource datasource = redisCache.getCacheObject(getCacheKey(id));
        if (StringUtils.isNotNull(datasource)) {
            return datasource;
        }
        ApiDatasource apiDatasource = apiDatasourceMapper.selectById(id);
        if (StringUtils.isNotNull(apiDatasource)) {
            redisCache.setCacheObject(getCacheKey(id), apiDatasource);
            return apiDatasource;
        }
        return null;
    }

    /**
     * 获取数据源列表
     */
    public List<ApiDatasource> getAll() {
        QueryWrapper<ApiDatasource> queryWrapper = new QueryWrapper<ApiDatasource>();
        List<ApiDatasource> list = apiDatasourceMapper.selectList(queryWrapper.orderByDesc("update_time"));
        return list;
    }

    /**
     * 根据id获取数据源类型
     */
    public String getDBType(Integer id) {
        return apiDatasourceMapper.selectById(id).getType();
    }

    /**
     * 根据ids批量查询
     */
    public List<ApiDatasource> selectBatch(List<String> ids) {
        List<ApiDatasource> dataSources = apiDatasourceMapper.selectBatchIds(ids);
        dataSources.stream().forEach((ApiDatasource apiDatasource) -> {
                apiDatasource.setUpdateBy(null);
                apiDatasource.setUpdateTime(null);
                apiDatasource.setCreateBy(null);
                apiDatasource.setCreateTime(null);
            }
        );
        return dataSources;
    }

    /**
     * 根据ids批量插入
     */
    @Transactional
    public void insertBatch(List<ApiDatasource> list) {
        try {
            list.forEach(t -> {
                t.setCreateTime(new Date());
                t.setCreateBy(SecurityUtils.getLoginUser().getUsername());
                t.setUpdateTime(new Date());
                t.setUpdateBy(SecurityUtils.getLoginUser().getUsername());
                SecurityUtils.getLoginUser();
                apiDatasourceMapper.insert(t);
            });
        }
        catch (Exception e) {
            log.error("数据源导入失败",e.getMessage());
            throw new ServiceException("数据源导入失败", HttpStatus.ERROR);
        }

    }


    /**
     * 项目启动时，初始化数据源到缓存
     */
    @PostConstruct
    public void init() {
        clearDatasourceCache();
        loadingDatasourceCache();
    }

    /**
     * 加载数据源缓存数据
     */
    @Override
    public void loadingDatasourceCache() {
        List<ApiDatasource> list = apiDatasourceMapper.selectList(null);
        for (ApiDatasource config : list) {
            redisCache.setCacheObject(getCacheKey(config.getId()), config);
        }
    }

    /**
     * 清空数据源缓存数据
     */
    @Override
    public void clearDatasourceCache() {
        Collection<String> keys = redisCache.keys(Constants.API_DATASOURCE_KEY + "*");
        redisCache.deleteObject(keys);
    }

    /**
     * 设置cache key
     *
     * @param configKey 参数键
     * @return 缓存键key
     */
    private String getCacheKey(String configKey) {
        return Constants.API_DATASOURCE_KEY + configKey;
    }

}
